"""
Flowable REST API 客户端封装
用于 Python 后端与 Flowable 工作流引擎集成
"""
import requests
from typing import Dict, List, Optional, Any
from requests.auth import HTTPBasicAuth


class FlowableClient:
    """Flowable REST API 客户端"""
    
    def __init__(self, base_url: str, username: str = "admin", password: str = "test"):
        """
        初始化 Flowable 客户端
        
        Args:
            base_url: Flowable REST API 基础URL，如 http://localhost:8081/flowable-rest
            username: 用户名
            password: 密码
        """
        self.base_url = base_url.rstrip('/')
        self.auth = HTTPBasicAuth(username, password)
        self.session = requests.Session()
        self.session.auth = self.auth
        
    def _request(self, method: str, endpoint: str, **kwargs) -> requests.Response:
        """发送 HTTP 请求"""
        url = f"{self.base_url}{endpoint}"
        response = self.session.request(method, url, **kwargs)
        response.raise_for_status()
        return response
    
    # ========== 流程定义相关 ==========
    
    def deploy_process(self, bpmn_file_path: str) -> Dict:
        """
        部署流程定义
        
        Args:
            bpmn_file_path: BPMN 文件路径
            
        Returns:
            部署信息
        """
        with open(bpmn_file_path, 'rb') as f:
            files = {'file': (bpmn_file_path.split('/')[-1], f, 'application/xml')}
            response = self._request('POST', '/service/repository/deployments', files=files)
            return response.json()
    
    def get_process_definitions(self, key: Optional[str] = None) -> List[Dict]:
        """
        获取流程定义列表
        
        Args:
            key: 流程定义key（可选）
            
        Returns:
            流程定义列表
        """
        params = {}
        if key:
            params['key'] = key
        response = self._request('GET', '/service/repository/process-definitions', params=params)
        return response.json().get('data', [])
    
    # ========== 流程实例相关 ==========
    
    def start_process(self, process_key: str, variables: Optional[Dict] = None, 
                     business_key: Optional[str] = None) -> Dict:
        """
        启动流程实例
        
        Args:
            process_key: 流程定义key
            variables: 流程变量
            business_key: 业务key（可选）
            
        Returns:
            流程实例信息
        """
        data = {
            'processDefinitionKey': process_key
        }
        if business_key:
            data['businessKey'] = business_key
        if variables:
            data['variables'] = [
                {'name': k, 'value': v} for k, v in variables.items()
            ]
        
        response = self._request('POST', '/service/runtime/process-instances', json=data)
        return response.json()
    
    def get_process_instance(self, process_instance_id: str) -> Dict:
        """
        获取流程实例详情
        
        Args:
            process_instance_id: 流程实例ID
            
        Returns:
            流程实例信息
        """
        response = self._request('GET', f'/service/runtime/process-instances/{process_instance_id}')
        return response.json()
    
    def get_process_instances(self, process_key: Optional[str] = None, 
                              business_key: Optional[str] = None) -> List[Dict]:
        """
        获取流程实例列表
        
        Args:
            process_key: 流程定义key（可选）
            business_key: 业务key（可选）
            
        Returns:
            流程实例列表
        """
        params = {}
        if process_key:
            params['processDefinitionKey'] = process_key
        if business_key:
            params['businessKey'] = business_key
        
        response = self._request('GET', '/service/runtime/process-instances', params=params)
        return response.json().get('data', [])
    
    def delete_process_instance(self, process_instance_id: str, 
                                delete_reason: Optional[str] = None) -> None:
        """
        删除流程实例
        
        Args:
            process_instance_id: 流程实例ID
            delete_reason: 删除原因（可选）
        """
        params = {}
        if delete_reason:
            params['deleteReason'] = delete_reason
        self._request('DELETE', f'/service/runtime/process-instances/{process_instance_id}', 
                     params=params)
    
    def get_process_variables(self, process_instance_id: str) -> Dict:
        """
        获取流程变量
        
        Args:
            process_instance_id: 流程实例ID
            
        Returns:
            流程变量字典
        """
        response = self._request('GET', 
                                f'/service/runtime/process-instances/{process_instance_id}/variables')
        variables = {}
        for var in response.json():
            variables[var['name']] = var['value']
        return variables
    
    def set_process_variable(self, process_instance_id: str, variable_name: str, 
                            variable_value: Any) -> None:
        """
        设置流程变量
        
        Args:
            process_instance_id: 流程实例ID
            variable_name: 变量名
            variable_value: 变量值
        """
        data = {
            'name': variable_name,
            'value': variable_value
        }
        self._request('PUT', 
                     f'/service/runtime/process-instances/{process_instance_id}/variables/{variable_name}',
                     json=data)
    
    # ========== 任务相关 ==========
    
    def get_tasks(self, assignee: Optional[str] = None, 
                 candidate_user: Optional[str] = None,
                 candidate_group: Optional[str] = None,
                 process_key: Optional[str] = None) -> List[Dict]:
        """
        获取任务列表
        
        Args:
            assignee: 任务分配人（可选）
            candidate_user: 候选用户（可选）
            candidate_group: 候选组（可选）
            process_key: 流程定义key（可选）
            
        Returns:
            任务列表
        """
        params = {}
        if assignee:
            params['assignee'] = assignee
        if candidate_user:
            params['candidateUser'] = candidate_user
        if candidate_group:
            params['candidateGroup'] = candidate_group
        if process_key:
            params['processDefinitionKey'] = process_key
        
        response = self._request('GET', '/service/runtime/tasks', params=params)
        return response.json().get('data', [])
    
    def get_task(self, task_id: str) -> Dict:
        """
        获取任务详情
        
        Args:
            task_id: 任务ID
            
        Returns:
            任务信息
        """
        response = self._request('GET', f'/service/runtime/tasks/{task_id}')
        return response.json()
    
    def claim_task(self, task_id: str, user_id: str) -> None:
        """
        认领任务
        
        Args:
            task_id: 任务ID
            user_id: 用户ID
        """
        data = {'userId': user_id}
        self._request('POST', f'/service/runtime/tasks/{task_id}/claim', json=data)
    
    def complete_task(self, task_id: str, variables: Optional[Dict] = None) -> None:
        """
        完成任务
        
        Args:
            task_id: 任务ID
            variables: 任务变量（可选）
        """
        data = {}
        if variables:
            data['variables'] = [
                {'name': k, 'value': v} for k, v in variables.items()
            ]
        self._request('POST', f'/service/runtime/tasks/{task_id}', json=data)
    
    def delegate_task(self, task_id: str, user_id: str) -> None:
        """
        委托任务
        
        Args:
            task_id: 任务ID
            user_id: 被委托用户ID
        """
        data = {'userId': user_id}
        self._request('POST', f'/service/runtime/tasks/{task_id}/delegate', json=data)
    
    # ========== 历史数据相关 ==========
    
    def get_historic_process_instances(self, process_key: Optional[str] = None,
                                      business_key: Optional[str] = None,
                                      finished: Optional[bool] = None) -> List[Dict]:
        """
        获取历史流程实例
        
        Args:
            process_key: 流程定义key（可选）
            business_key: 业务key（可选）
            finished: 是否已完成（可选）
            
        Returns:
            历史流程实例列表
        """
        params = {}
        if process_key:
            params['processDefinitionKey'] = process_key
        if business_key:
            params['processBusinessKey'] = business_key
        if finished is not None:
            params['finished'] = finished
        
        response = self._request('GET', '/service/history/historic-process-instances', params=params)
        return response.json().get('data', [])
    
    def get_historic_tasks(self, process_instance_id: Optional[str] = None,
                          assignee: Optional[str] = None) -> List[Dict]:
        """
        获取历史任务
        
        Args:
            process_instance_id: 流程实例ID（可选）
            assignee: 任务分配人（可选）
            
        Returns:
            历史任务列表
        """
        params = {}
        if process_instance_id:
            params['processInstanceId'] = process_instance_id
        if assignee:
            params['assignee'] = assignee
        
        response = self._request('GET', '/service/history/historic-task-instances', params=params)
        return response.json().get('data', [])


# 使用示例
if __name__ == '__main__':
    # 初始化客户端
    client = FlowableClient(
        base_url="http://localhost:8081/flowable-rest",
        username="admin",
        password="test"
    )
    
    # 启动采购申请流程
    process_instance = client.start_process(
        process_key="purchaseApproval",
        business_key="PUR-2024-001",
        variables={
            "purchaseAmount": 60000,
            "projectManagerId": "user123",
            "materialName": "消防设备",
            "quantity": 10
        }
    )
    print(f"流程实例ID: {process_instance['id']}")
    
    # 查询待办任务
    tasks = client.get_tasks(candidate_user="user123")
    print(f"待办任务数: {len(tasks)}")
    
    # 完成任务
    if tasks:
        task_id = tasks[0]['id']
        client.complete_task(
            task_id=task_id,
            variables={
                "approvalResult": "approved",
                "approvalComment": "同意采购"
            }
        )
        print(f"任务 {task_id} 已完成")

